/**
 * 
 */
package org.swing.utility.jai.geometry;

import java.awt.Polygon;
import java.lang.reflect.Array;

/**
 * @author lqnhu
 *
 */
public class FlipPolygon extends Polygon {
	/**
	 * Creates a new empty FlipPolygon.
	 */
	public FlipPolygon() {
		super();
	}

	/**
	 * Same as the longer FlipPolygon constructor only it uses the length of
	 * either xpoints or ypoints as the number of points. For a valid polygon
	 * they should both be of equal length, so it does not matter which is used.
	 * 
	 * @param xpoints
	 *            The xpoints for this polygon.
	 * @param ypoints
	 *            The ypoints for this polygon.
	 */
	public FlipPolygon(int[] xpoints, int[] ypoints) {
		this(xpoints, ypoints, xpoints.length);
	}

	/**
	 * Creates a new FlipPolygon which will contain the given points. The length
	 * of xpoints and ypoints must be equal to npoints.
	 * 
	 * @param xpoints
	 *            The X-axis points for this polygon.
	 * @param ypoints
	 *            The Y-axis points for this polygon.
	 * @param npoints
	 *            The number of points stored in this polygon.
	 */
	public FlipPolygon(int[] xpoints, int[] ypoints, int npoints) {
		super(xpoints, ypoints, npoints);
	}

	/**
	 * @return A clone of this but with points flipped along the X axis.
	 */
	public FlipPolygon flipX() {
		return new FlipPolygon(flip(xpoints),
				ArrayUtil.copyOf(ypoints, npoints), npoints);
	}

	/**
	 * @return A clone of this but with points flipped along the Y axis.
	 */
	public FlipPolygon flipY() {
		return new FlipPolygon(ArrayUtil.copyOf(xpoints, npoints),
				flip(ypoints), npoints);
	}

	/**
	 * @return A copy of this only with points flipped on both the X and Y axis.
	 */
	public FlipPolygon flipXY() {
		return new FlipPolygon(flip(xpoints), flip(ypoints), npoints);
	}

	/**
	 * @param points
	 * @return A copy of points only with all it's elements flipped around 0.
	 */
	private int[] flip(int[] points) {
		final int[] newPoints = new int[points.length];
		for (int i = 0; i < points.length; i++) {
			newPoints[i] = -points[i];
		}
		return newPoints;
	}

	/**
	 * @return A clone of this only with it's x and y points swapped.
	 */
	public FlipPolygon swapXT() {
		return new FlipPolygon(ArrayUtil.copyOf(ypoints, npoints),
				ArrayUtil.copyOf(xpoints, npoints), npoints);
	}

	/**
	 * @return A FlipPolygon with the same points as this one.
	 * @throws java.lang.CloneNotSupportedException
	 *             Will not be thrown by this implementation of the method.
	 */
	@Override
	protected FlipPolygon clone() throws CloneNotSupportedException {
		return new FlipPolygon(ArrayUtil.copyOf(xpoints, npoints),
				ArrayUtil.copyOf(ypoints, npoints), npoints);
	}
}

/**
 * This is a fully static class offering some common utility functions for
 * working with arrays. Some of these functions are built for Java 5
 * compatibility.
 *
 * @author Joseph Lenton - JosephLenton@StudioFortress.com
 */
final class ArrayUtil {
	/**
	 * No Construstor.
	 */
	private ArrayUtil() {
	}

	public static <A> A[] copyOf(final A[] arr) {
		return copyOf(arr, arr.length);
	}

	public static <A> A[] copyOf(final A[] arr, int newSize) {
		return (A[]) copyOf(arr, newSize, arr.getClass());
	}

	private static <T, U> T[] copyOf(U[] arr, int newSize,
			Class<? extends T[]> newType) {
		T[] copy = ((Object) newType == (Object) Object[].class) ? (T[]) new Object[newSize]
				: (T[]) Array.newInstance(newType.getComponentType(), newSize);
		System.arraycopy(arr, 0, copy, 0, Math.min(arr.length, newSize));
		return copy;
	}

	public static int[] copyOf(final int[] arr) {
		return copyOf(arr, arr.length);
	}

	public static int[] copyOf(final int[] arr, int newSize) {
		final int[] tempArr = new int[newSize];
		System.arraycopy(arr, 0, tempArr, 0, Math.min(arr.length, newSize));
		return tempArr;
	}

	public static double[] copyOf(final double[] arr) {
		return copyOf(arr, arr.length);
	}

	public static double[] copyOf(final double[] arr, int newSize) {
		final double[] tempArr = new double[newSize];
		System.arraycopy(arr, 0, tempArr, 0, Math.min(arr.length, newSize));
		return tempArr;
	}

	public static float[] copyOf(final float[] arr) {
		return copyOf(arr, arr.length);
	}

	public static float[] copyOf(final float[] arr, int newSize) {
		final float[] tempArr = new float[newSize];
		System.arraycopy(arr, 0, tempArr, 0, Math.min(arr.length, newSize));
		return tempArr;
	}

	public static byte[] copyOf(final byte[] arr) {
		return copyOf(arr, arr.length);
	}

	public static byte[] copyOf(final byte[] arr, int newSize) {
		final byte[] tempArr = new byte[newSize];
		System.arraycopy(arr, 0, tempArr, 0, Math.min(arr.length, newSize));
		return tempArr;
	}

	public static char[] copyOf(final char[] arr) {
		return copyOf(arr, arr.length);
	}

	public static char[] copyOf(final char[] arr, int newSize) {
		final char[] tempArr = new char[newSize];
		System.arraycopy(arr, 0, tempArr, 0, Math.min(arr.length, newSize));
		return tempArr;
	}

	public static long[] copyOf(final long[] arr) {
		return copyOf(arr, arr.length);
	}

	public static long[] copyOf(final long[] arr, int newSize) {
		final long[] tempArr = new long[newSize];
		System.arraycopy(arr, 0, tempArr, 0, Math.min(arr.length, newSize));
		return tempArr;
	}

	public static boolean[] copyOf(final boolean[] arr) {
		return copyOf(arr, arr.length);
	}

	public static boolean[] copyOf(final boolean[] arr, int newSize) {
		final boolean[] tempArr = new boolean[newSize];
		System.arraycopy(arr, 0, tempArr, 0, Math.min(arr.length, newSize));
		return tempArr;
	}
}
